package com.wms.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wms.bean.PageBean;
import com.wms.bean.ResultBean;
import com.wms.core.R;
import com.wms.dto.*;
import com.wms.entity.*;
import com.wms.mapper.CategoryMapper1;
import com.wms.mapper.MaterialMapper;
import com.wms.mapper.StockInMapper;
import com.wms.service.StockInService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
@Service
@EnableTransactionManagement
@Slf4j
public class StockInServiceImpl implements StockInService {
    @Autowired
    StockInMapper stockInMapper;
    @Autowired
    MaterialMapper materialMapper;
    @Autowired
    CategoryMapper1 categoryMapper1;

    /**
     * 分页查询加工入库记录
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageBean queryProcessInTask(int page,int pageSize,ProcessIn process) {
        PageHelper.startPage(page,pageSize);
        List<ProcessIn> list= stockInMapper.getProcessInTask(process);
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize,info.getTotal(),list);
    }

    /**
     * 分页查询采购入库任务单
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageBean queryPurchaseStockInTask(int page, int pageSize, PurchaseStockIn stock) {
        //查询前实时更新逻辑删除状态
        stockInMapper.updateStockInSuccess();
        PageHelper.startPage(page,pageSize);
        List<PurchaseStockIn> list= stockInMapper.getPurchaseStockInTask(stock);
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize,info.getTotal(),list);
    }

    @Override
    public PageBean queryPurchaseStockInDetail(int page, int pageSize, PurchaseDetailDTO stock) {
        //查询前实时更新逻辑删除状态
        stockInMapper.updateStockInSuccess();
        PageHelper.startPage(page,pageSize);
        List<PurchaseDetailDTO> list=stockInMapper.getPurchaseStockInDetail(stock);
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize,info.getTotal(),list);
    }

    /**
     * 分页查询质检后的采购入库任务
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageBean queryPQInTask(int page, int pageSize) {
        PageHelper.startPage(page, pageSize);
        List<Map<String,Object>> list=stockInMapper.getPQInTask();
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize,info.getTotal(),list);
    }

    /**
     * 分页查询直接入库任务单
     * @param page
     * @param pageSize
     * @param direct
     * @return
     */
    @Override
    public PageBean queryDirectInTask(int page, int pageSize, DirectInDTO direct) {
        PageHelper.startPage(page,pageSize);
        List<Map<String,Object>> list=stockInMapper.getDirectInTask(direct);
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize, info.getTotal(),list);
    }

    /**
     * 分页查询直接入库任务详情
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageBean queryDirectInDetail(int page, int pageSize, DirectInDetailDTO direct) {
        PageHelper.startPage(page,pageSize);
        List<Map<String,Object>> list=stockInMapper.getDirectInDetail(direct);
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize,info.getTotal(),list);
    }

    /**
     * 提交入库
     * @param list
     * @return
     */
    @Transactional
    public ResultBean addPQInTask(List<MasDTO> list){
       try{
           list.forEach(s->{
               //添加物料库存的参数
               Stock stock=new Stock();
               String batchNo=s.getBatchNo();
               Integer mid=s.getMid();
               String inTime=LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
               //执行入库操作时更新批次表中的入库时间
               stockInMapper.updateBatchNum(batchNo,mid,inTime);
               if (null!=materialMapper.queryStock(s.getMid())){
                   stock.setId(s.getMid());
                   stock.setNum(s.getStock()+materialMapper.queryStock(s.getMid()).getNum());
                   stock.setAvailableNum(s.getStock()+materialMapper.queryStock(s.getMid()).getAvailableNum());
                   stock.setUpdateBy(s.getCreateBy().toString());
                   //更新物料库存表
                   materialMapper.updateStock(stock);
               }else {
                   stock.setId(s.getMid());
                   stock.setNum(s.getStock());
                   stock.setAvailableNum(s.getStock());
                   stock.setCreateBy(s.getCreateBy().toString());
                   materialMapper.insertStock(stock);
               }
               //更改表详情中的已入库数量
               stockInMapper.updateStockDetail(s.getStock(),s.getProductCode());
               //判断该库区是否存在该批次的物料
               if (null!=stockInMapper.queryMASStock(s)){
                   MasDTO dto=new MasDTO();
                   dto.setMid(s.getMid());
                   dto.setStock(s.getStock()+stockInMapper.queryMASStock(s).getStock());
                   dto.setAvailableNum(s.getStock()+stockInMapper.queryMASStock(s).getStock());
                   dto.setUpdateBy(s.getUpdateBy());
                   dto.setAreaId(s.getAreaId());
                   dto.setBatchNo(s.getBatchNo());
                   stockInMapper.updateMASStock(dto);
               }else {
                   s.setAvailableNum(s.getStock());
                   stockInMapper.saveMAS(s);
               }
               //定义添加入库记录的参数
               StockInRecord record=stockInMapper.getRecodeNeeds(s.getDid());
               System.out.println(record.getInStockQty());
               record.setInStockQty(s.getStock());
               stockInMapper.saveStockInRecord(record);
           });
       } catch (Exception e){
           return R.fail("入库失败",e);
       }
        return R.success("入库完成!");
    }

    /**
     * 删除指定采购任务详情
     * @param id
     * @return
     */
    @Override
    public int deletePurchaseStockInDetail(int id) {
        return stockInMapper.removeStockDetail(id);
    }

    /**
     * 添加产品/商品直接入库任务单;同时添加任务详情 一个任务单可以对应多条详情记录
     * @param direct
     * @return
     */
    @Transactional

    @Override
    public int addDirectInTask(DirectIn direct,List<DirectInDetail> list)  {
        //在前端勾选返回的数据存入list集合
        int num=0;
        int status=1;
        //自动生成批次号,并将批次号插入到批次表中
        String newBatchNum=getDirectBatchNum();
        direct.setBatchNum(newBatchNum);
        List<BatchNum> list1=new ArrayList<>();
        for (DirectInDetail d : list) {
            BatchNum batchNum=new BatchNum();
            batchNum.setMid(d.getProductId());
            batchNum.setBatchNo(newBatchNum);
            list1.add(batchNum);
            //统计此次任务数量
            num++;
            //设置任务单入库物品类型以及温区,同一任务单的入库任务二者必须一致
            direct.setProductType(d.getProductType());
            direct.setWarmArea(d.getWarmArea());
            //通过查询详情入库状态来确定任务单入库状态
            if (d.getInStatus()==2){
                status=2;
            }
            //将任务详情的任务单id设为目前数据库中最大任务单id+1
            d.setTaskId(stockInMapper.getMaxDirectInTaskId()+1);
        }
        //插入批次表
        stockInMapper.saveBatchNum(list1);
        direct.setStockStatus(status);
        direct.setTaskNum(num);
        //实际要从前端选择类型返回的数据设置
        direct.setProductType(1);
        //自动生成任务单编码
        direct.setInCode(getNewZJTaskCode());
        //
        stockInMapper.saveDirectInTaskDetail(list);
        return stockInMapper.saveDirectInTask(direct);
    }

    /**
     * 生成采购入库任务单及任务明细
     * @param arrival
     * @return
     */
    @Override
    public int addPurchaseInTask(Arrival arrival) {
        PurchaseStockIn task=new PurchaseStockIn();
        task.setArrivalCode(arrival.getArrivalCode());
        task.setPurchaseCode(arrival.getPurchaseCode());
        task.setSupplier(arrival.getSupplierName());
        task.setArrivalDate(arrival.getArrivalDate());
        task.setAddType(arrival.getAddType());
        task.setStockStatus(1);
        task.setPurchaseUser(arrival.getPurchaseUser());
        task.setProductType(arrival.getProductType());
        //获取当前最大任务单id+1
        int num;
        if (null!=stockInMapper.getMaxPurchaseInTaskId()){
            num=stockInMapper.getMaxPurchaseInTaskId()+1;
        }else num=1;
        task.setId(num);
        //生成任务编码
        task.setTaskCode(getNewCGTaskCode());
        task.setPurchaseDate(arrival.getPurchaseDate());
        List<PurchaseStockInDetail> details=new ArrayList<>();
        arrival.getArrivalDetailList().forEach(el->{
            PurchaseStockInDetail detail=new PurchaseStockInDetail();
            detail.setProductName(el.getName());
            detail.setProductCode(el.getMcode());
            detail.setSpec(el.getSpec());
            detail.setArrivalNum(el.getArrivalNum());
            detail.setInNum(0);
            detail.setCategory(el.getCategory());
            detail.setUnit(el.getUnit());
            detail.setStatus(0);
            detail.setTaskId(task.getId());
            task.setBatchNum(el.getBatchNum());
            details.add(detail);
        });
        task.setPurchaseStockInDetails(details);
        //分别向任务表和任务详情表中插入数据
        int rs=stockInMapper.savePurchaseInTask(task);
        stockInMapper.savePurchaseInDetailTask(details);
        return rs;
    }
    /**
     * 通用批次号生成方法（抽取重复逻辑）
     * @param prefix 批次号前缀（如ZJPC、JGPC）
     * @param maxBatchNoQueryFunc 查询最大批次号的函数（通过函数式接口传递不同Mapper查询）
     * @return 格式化后的批次号
     */
    private String generateBatchNum(String prefix, Supplier<String> maxBatchNoQueryFunc) {
        int retryCount = 3;
        while (retryCount > 0) {
            try {
                String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                String maxBatchNo = maxBatchNoQueryFunc.get(); // 执行不同的Mapper查询
                String newBatchNo;
                if (maxBatchNo == null) {
                    newBatchNo = prefix + date + "0001";
                } else {
                    if (maxBatchNo.length() != prefix.length() + 8 + 4) {
                        throw new IllegalArgumentException("历史编码格式非法:" + maxBatchNo);
                    }
                    String maxDate = maxBatchNo.substring(prefix.length(), prefix.length() + 8);
                    if (maxDate.equals(date)) {
                        int seq = Integer.parseInt(maxBatchNo.substring(prefix.length() + 8));
                        String seqStr = String.format("%4d", seq + 1);
                        newBatchNo = prefix + date + seqStr;
                    } else {
                        newBatchNo = prefix + date + "0001";
                    }
                }
                return newBatchNo;
            } catch (Exception e) {
                retryCount--;
                log.error("生成{}类型批次号失败，剩余重试次数：{}", prefix, retryCount, e);
                if (retryCount == 0) {
                    throw new RuntimeException("生成" + prefix + "类型批次号失败", e);
                }
            }
        }
        throw new RuntimeException("生成" + prefix + "类型批次号失败");
    }

    // 直接入库批次号
    private String getDirectBatchNum() {
        return generateBatchNum("ZJPC", stockInMapper::getMaxDirectBatchNum);
    }

    // 加工入库批次号
    private String getProcessBatchNum() {
        return generateBatchNum("JGPC", stockInMapper::getMaxProcessBatchNum);
    }

    /**
     * 添加加工入库任务(类似添加直接入库)
     * @param process
     * @param list
     * @return
     */
    @Transactional
    @Override
    public int addProcessInTask(ProcessIn process, List<ProcessInDetail> list) {
        //在前端勾选返回的数据存入list集合
        Material material=new Material();
        int num=0;
        //自动生成批次号,并将批次号插入到批次表中
        String newBatchNum=getProcessBatchNum();
        process.setBatchNum(newBatchNum);
        List<BatchNum> list1=new ArrayList<>();
        for (ProcessInDetail p : list) {
            BatchNum batchNum=new BatchNum();
            Integer mid=materialMapper.queryMaterialByCode(p.getGoodsCode());
            //查询是否存在该物料,若存在直接绑定
            if (null!=mid){
                batchNum.setMid(mid);
            }else {
                //不存在,现在物料表中新增再绑定
                material.setCategoryName(p.getCategory());
                material.setName(p.getGoodsName());
                material.setCode(p.getGoodsCode());
                material.setSpec(p.getSpec());
                material.setUnit(p.getUnit());
                materialMapper.addMaterial(material);
            }
            batchNum.setBatchNo(newBatchNum);
            list1.add(batchNum);
            //统计此次任务数量
            num++;
            //将任务详情的任务单id设为目前数据库中最大任务单id+1
            p.setTaskId(stockInMapper.getMaxProcessInTaskId()+1);
        }
        //插入批次表
        stockInMapper.saveBatchNum(list1);
        process.setTaskNum(num);
        //自动生成任务编号
        process.setTaskCode(getNewJGTaskCode());
        //
        stockInMapper.saveProcessInDetail(list);
        return stockInMapper.saveProcessInTask(process);
    }

    /**
     * 查询加工入库详情
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageBean queryProcessInDetail(int page, int pageSize,ProcessInDetailDTO process) {
        PageHelper.startPage(page,pageSize);
        List<ProcessInDetail> list=stockInMapper.getProcessInDetail(process);
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize,info.getTotal(),list);
    }

    /**
     * 条件查询入库记录
     * @param page
     * @param pageSize
     * @param record
     * @return
     */
    @Override
    public PageBean queryStockInRecords(int page, int pageSize, RecordDTO record) {
        PageHelper.startPage(page,pageSize);
        List<StockInRecord> list=stockInMapper.getStockRecord(record);
        PageInfo info=new PageInfo(list);
        return new PageBean(page,pageSize,info.getTotal(),list);
    }

    // 通用生成编码方法

    /**
     * 通用任务编码生成方法(抽取重复逻辑)
     * @param prefix 任务编码前缀(如ZJRK,CGRK)
     * @param maxCodeSupplier 查询最大任务编码的函数(通过函数式接口传递不同Mapper查询)
     * @return 格式化后的任务编码
     */
    private String getNewTaskCode(String prefix, Supplier<String> maxCodeSupplier) {
        int retryCount = 3;
        while (retryCount > 0) {
            try {
                String maxCode = maxCodeSupplier.get(); // 传入获取最大编码的逻辑（如stockInMapper::getMaxPurchaseInTaskCode）
                String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
                String newCode;
                if (null == maxCode) {
                    newCode = prefix + date + "001";
                } else {
                    // 校验maxCode格式（前缀长度+年月长度是否匹配）
                    if (maxCode.length() != prefix.length() + 6 + 3) {
                        throw new IllegalArgumentException("历史编码格式非法：" + maxCode);
                    }
                    String maxDate = maxCode.substring(prefix.length(), prefix.length() + 6);
                    if (maxDate.equals(date)) {
                        int seq = Integer.parseInt(maxCode.substring(prefix.length() + 6));
                        String seqStr = String.format("%03d", seq + 1);
                        newCode = prefix + date + seqStr;
                    } else {
                        newCode = prefix + date + "001";
                    }
                }
                // 此处可增加编码存在性校验（调用Mapper.countTaskCode(newCode)）
                return newCode;
            } catch (Exception e) {
                retryCount--;
                log.error("生成{}类型入库编码失败，剩余重试次数：{}", prefix, retryCount, e);
                if (retryCount == 0) {
                    throw new RuntimeException("生成" + prefix + "类型入库编码失败", e);
                }
            }
        }
        throw new RuntimeException("生成" + prefix + "类型入库编码失败");
    }

    // 采购入库编码（调用通用方法）
    private String getNewCGTaskCode() {
        return getNewTaskCode("CGRK", stockInMapper::getMaxPurchaseInTaskCode);
    }

    // 直接入库编码（调用通用方法）
    private String getNewZJTaskCode() {
        return getNewTaskCode("ZJRK", stockInMapper::getMaxDirectInTaskCode);
    }
    // 加工入库编码（调用通用方法）
    private String getNewJGTaskCode(){
        return getNewTaskCode("JGRK",stockInMapper::getMaxProcessInTaskCode);
    }
    private String getNewDBTaskCode(){return getNewTaskCode(("DBRK"),stockInMapper::getMaxDBInTaskCode);}
}
